home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / progtool / c / gcc / gempp19.zoo / gem++19 / src / gemhf.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-20  |  14.7 KB  |  593 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  This file is Copyright 1992,1993 by Warwick W. Allison.
  4. //  This file is part of the gem++ library.
  5. //  You are free to copy and modify these sources, provided you acknowledge
  6. //  the origin by retaining this notice, and adhere to the conditions
  7. //  described in the file COPYING.LIB.
  8. //
  9. /////////////////////////////////////////////////////////////////////////////
  10.  
  11. #include <aesbind.h>
  12. #include <values.h>
  13. #include "gemhf.h"
  14. #include "gemrawo.h"
  15. #include "grect.h"
  16.  
  17.  
  18. static int FindEdit(GEMrawobject* o, int i)
  19. {
  20.     return o[i].Editable() ? i : -1;
  21. }
  22.  
  23. GEMhotform::GEMhotform(const GEMrsc& in, int RSCindex) :
  24.     GEMform(in,RSCindex)
  25. {
  26.     curedit=Map(FindEdit);
  27.     Zooms(FALSE);
  28. }
  29.  
  30. GEMhotform::GEMhotform(const GEMhotform& copy) :
  31.     GEMform(copy)
  32. {
  33.     curedit=Map(FindEdit);
  34.     Zooms(FALSE);
  35. }
  36.  
  37. int GEMhotform::DoKey(int meta, int key)
  38. {
  39.     return Ignore;
  40. }
  41.  
  42. int GEMhotform::DoOff()
  43. {
  44.     return NoObject;
  45. }
  46.  
  47. int GEMhotform::DoHot(int ob, bool inside)
  48. {
  49.     static void objc_toggle(GEMrawobject* tree, int obj);
  50.  
  51.     objc_toggle(Obj,ob);
  52.  
  53.     // Could use this, but G_STRING objects are transparent, so do not
  54.     // Redraw well when selected.
  55.     //
  56.     // Obj[ob].Selected(inside);
  57.     // RedrawObject(ob);
  58.  
  59.     return Ignore;
  60. }
  61.  
  62. // "Hot" version from Profesional GEM, by Tim Oren.
  63. //
  64. // The following code is based on the file "gemcl13.c" in the
  65. // source code provided with the Professional GEM series.
  66. // Available in the /atari/Programming directory of atari.archive.umich.edu.
  67. //
  68. // Changes include:
  69. //
  70. //      - Ported to C++ (ie. uses ANSI prototypes).
  71. //      - Uses current bindings.
  72. //      - Added "machine" macros #defines at start.
  73. //      - Clicking off form detected.
  74. //      - Unprocessed keys passed to DoKey() method.
  75.  
  76. #define NIL -1
  77.  
  78. #define    M1_ENTER    0x0000
  79. #define    M1_EXIT        0x0001
  80.  
  81. #define BS   0x0008
  82. #define    TAB  0x0009
  83. #define    CR   0x000D
  84. #define ESC  0x001B
  85. #define    BTAB 0x0f00
  86. #define    UP   0x4800
  87. #define    DOWN 0x5000
  88. #define    DEL  0x5300
  89.  
  90. /* Global variables used by */
  91. /* 'mapped' functions        */
  92.  
  93. static    GRect    br_rect;        /* Current break rectangle  */
  94. static    int    br_mx, br_my, br_togl;    /* Break mouse posn & flag  */ 
  95. static    int    fn_obj;            /* Found tabable object        */
  96. static    int    fn_last;        /* Object tabbing from        */
  97. static    int    fn_prev;        /* Last EDITABLE obj seen   */
  98. static    int    fn_dir;            /* 1 = TAB, 0 = BACKTAB        */
  99.  
  100. /************* Utility routines for new forms manager ***************/
  101.  
  102. /* Return the object's GRect through 'p' */
  103. static void objc_xywh(GEMrawobject* tree, int obj, GRect *p)
  104. {
  105.     objc_offset(tree, obj, &p->g_x, &p->g_y);
  106.     p->g_w = tree[obj].Width();
  107.     p->g_h = tree[obj].Height();
  108. }
  109.  
  110. /* Reverse the SELECT state */
  111. static void objc_toggle(GEMrawobject* tree, int obj)
  112. {
  113.     int    state, newstate;
  114.     GRect    root;
  115.  
  116.     objc_xywh(tree, ROOT, &root);
  117.     state = tree[obj].States();
  118.     newstate = state ^ SELECTED;
  119.     objc_change(tree, obj, 0, root.g_x, root.g_y, 
  120.         root.g_w, root.g_h, newstate, 1);
  121. }
  122.  
  123. /* If the object is not already SELECTED, make it so. */
  124. static void objc_sel(GEMrawobject* tree, int obj)
  125. {
  126.     if ( !(tree[obj].States() & SELECTED) )
  127.         objc_toggle(tree, obj);
  128. }
  129.  
  130. /* If the object is SELECTED, deselect it. */
  131. static void objc_dsel(GEMrawobject* tree, int obj)
  132. {
  133.     if (tree[obj].States() & SELECTED)
  134.         objc_toggle(tree, obj);
  135. }
  136.  
  137. /* Non-cursive traverse of an object tree. */
  138. static void map_tree(GEMrawobject* tree, int this1, int last, int routine(GEMrawobject*,int))
  139. {
  140.     int        tmp1;
  141.  
  142.     tmp1 = this1;        /* Initialize to impossible value: */
  143.                 /* TAIL won't point to self!       */
  144.                 /* Look until final node, or off   */
  145.                 /* the end of tree           */ 
  146.     while (this1 != last && this1 != NIL)
  147.                 /* Did we 'pop' into this1 node       */
  148.                 /* for the second time?           */
  149.         if (tree[this1].Tail() != tmp1)
  150.             {
  151.             tmp1 = this1;    /* This is a new node       */
  152.             this1 = NIL;
  153.                     /* Apply operation, testing  */
  154.                     /* for rejection of sub-tree */
  155.             if (!tree[tmp1].HideTree())
  156.                 if (routine(tree, tmp1))
  157.                     this1 = tree[tmp1].Head();
  158.                     /* Subtree path not taken,   */
  159.                     /* so traverse right         */    
  160.             if (this1 == NIL)
  161.                 this1 = tree[tmp1].Next();
  162.             }
  163.         else            /* Revisiting parent:          */
  164.                     /* No operation, move right  */
  165.             {
  166.             tmp1 = this1;
  167.             this1 = tree[tmp1].Next();
  168.             }
  169. }
  170.  
  171. /* Find the parent of an object of by traversing right */
  172. static int get_parent(GEMrawobject* tree, int obj)
  173. {
  174.     int        pobj;
  175.  
  176.     if (obj == NIL)
  177.         return (NIL);
  178.     pobj = tree[obj].Next();
  179.     if (pobj != NIL)
  180.     {
  181.       while( tree[pobj].Tail() != obj ) 
  182.       {
  183.         obj = pobj;
  184.         pobj = tree[obj].Next();
  185.       }
  186.     }
  187.     return(pobj);
  188.  
  189. /* determine if x,y is in rectangle    */
  190. static int inside(int x, int y, GRect *pt)    
  191. {
  192.     if ( (x >= pt->g_x) && (y >= pt->g_y) &&
  193.         (x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) )
  194.         return(TRUE);
  195.     else
  196.         return(FALSE);
  197.  
  198. /************* "Hot-spot" manager and subroutines  ***************/
  199.  
  200. static int break_x(int *pxy)
  201. {                /* Breaking object is right of    */
  202.     if (br_mx < pxy[0])        /* mouse.  Reduce width of     */
  203.         {            /* bounding rectangle.        */
  204.         br_rect.g_w = pxy[0] - br_rect.g_x;
  205.         return (TRUE);
  206.         }
  207.     if (br_mx > pxy[2])        /* Object to left.  Reduce width*/
  208.         {            /* and move rect. to right    */
  209.         br_rect.g_w += br_rect.g_x - pxy[2] - 1;
  210.         br_rect.g_x = pxy[2] + 1;
  211.         return (TRUE);
  212.         }
  213.     return (FALSE);            /* Mouse within object segment.    */
  214. }                /* Break attempt fails.        */
  215.  
  216. static int break_y(int *pxy)
  217. {
  218.     if (br_my < pxy[1])        /* Object below mouse.  Reduce    */
  219.         {            /* height of bounding rect.    */
  220.         br_rect.g_h = pxy[1] - br_rect.g_y;
  221.         return (TRUE);
  222.         }
  223.     if (br_my > pxy[3])        /* Object above mouse.  Reduce    */
  224.         {            /* height and shift downward.    */
  225.         br_rect.g_h += br_rect.g_y - pxy[3] - 1;
  226.         br_rect.g_y = pxy[3] + 1;
  227.         return (TRUE); 
  228.         }
  229.     /* Emergency escape test! Protection vs. turkeys who nest */
  230.     /* non-selectable objects inside of selectables.          */
  231.     if (br_mx >= pxy[0] && br_mx <= pxy[1])
  232.         {                /* Will X break fail?      */
  233.         br_rect.g_x = br_mx;        /* If so, punt!          */
  234.         br_rect.g_y = br_my;
  235.         br_rect.g_w = br_rect.g_h = 1;
  236.         return (TRUE);
  237.         }
  238.     return (FALSE);
  239. }
  240.  
  241. /* Called once per object to    */
  242. static int break_obj(GEMrawobject* tree, int obj)
  243. {
  244.     GRect    s;
  245.     int    flags, broken, pxy[4];
  246.  
  247.     objc_xywh(tree, obj, &s);
  248.     grect_to_array(&s, pxy);
  249.     if (!rc_intersect(&br_rect, &s))
  250.         return (FALSE);        /* Trivial rejection case     */
  251.  
  252.     flags = tree[obj].Flags();    /* Is this1 object a potential    */
  253.     if (flags & HIDETREE)        /* hot-spot?                 */
  254.         return (FALSE);
  255.     if ( !(flags & SELECTABLE) )
  256.         return (TRUE);
  257.     if (tree[obj].States() & DISABLED)
  258.         return (TRUE);
  259.  
  260.     for (broken = FALSE; !broken; ) /* This could take two passes     */
  261.         {            /* if the first break fails.       */
  262.         if (br_togl)
  263.             broken = break_x(pxy);
  264.         else
  265.             broken = break_y(pxy);
  266.         br_togl = !br_togl;
  267.         }
  268.     return (TRUE);
  269. }
  270.  
  271. /* Manages mouse rectangle events */
  272. static int form_hot(GEMrawobject* tree, int hot_obj, int mx, int my, GRect *rect, int *mode)
  273. {
  274.     GRect    root;
  275.     int    state;
  276.  
  277.     objc_xywh(tree, ROOT, &root);    /* If there is already a hot-spot */
  278.  
  279.     if (!(inside(mx, my, &root)) )    /* Mouse has moved outside of       */
  280.         {            /* the dialog.  Wait for return.  */
  281.         *mode = M1_ENTER;
  282.         rc_copy(&root, rect);
  283.         return (NIL);
  284.         }
  285.                     /* What object is mouse over?      */
  286.                     /* (Hit is guaranteed.)           */
  287.     hot_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
  288.                     /* Is this object a hot-spot?      */
  289.     state = tree[hot_obj].States();
  290.     if (tree[hot_obj].Flags() & SELECTABLE)
  291.     if ( !(state & DISABLED) )
  292.         {            /* Yes!  Set up wait state.      */
  293.         *mode = M1_EXIT;
  294.         objc_xywh(tree, hot_obj, rect);
  295.         if (state & SELECTED)    /* But only toggle if it's not      */
  296.             return (NIL);    /* already SELECTED!          */
  297.         else
  298.             {
  299.             return (hot_obj);
  300.             }
  301.         }
  302.  
  303.     rc_copy(&root, &br_rect);    /* No hot object, so compute    */
  304.     br_mx = mx;            /* mouse bounding rectangle.    */
  305.     br_my = my;
  306.     br_togl = 0;
  307.     map_tree(tree, ROOT, NIL, break_obj);
  308.     rc_copy(&br_rect, rect);    /* Then return to wait state.    */
  309.     *mode = M1_EXIT;
  310.     return (NIL);
  311. }
  312.  
  313. /************* Keyboard manager and subroutines ***************/
  314.  
  315. /* Check if the object is DEFAULT    */
  316. static int find_def(GEMrawobject* tree, int obj)
  317.     {            /* Is sub-tree hidden?            */
  318.     if (HIDETREE & tree[obj].Flags())
  319.         return (FALSE);
  320.                 /* Must be DEFAULT and not DISABLED    */
  321.     if (DEFAULT & tree[obj].Flags())
  322.     if ( !(DISABLED & tree[obj].States()) )
  323.         fn_obj = obj;    /* Record object number            */
  324.     return (TRUE);
  325. }
  326.  
  327. /* Look for target of TAB operation.    */
  328. static int find_tab(GEMrawobject* tree, int obj)
  329.     {            /* Check for hiddens subtree.        */
  330.     if (HIDETREE & tree[obj].Flags())
  331.         return (FALSE);
  332.                 /* If not EDITABLE, who cares?        */
  333.     if ( !(EDITABLE & tree[obj].Flags()) )
  334.         return (TRUE);
  335.                 /* Check for forward tab match        */
  336.     if (fn_dir && fn_prev == fn_last)
  337.         fn_obj = obj;
  338.                 /* Check for backward tab match        */
  339.     if (!fn_dir && obj == fn_last)
  340.         fn_obj = fn_prev;
  341.     fn_prev = obj;        /* Record object for next call.        */
  342.     return (TRUE);
  343. }    
  344.  
  345. static int form_keyboard(GEMrawobject* tree, int edit_obj, int next_obj, int kr, int *out_obj, int *okr)
  346. {
  347.     if (kr&0xff)        /* If lower byte valid, mask out    */
  348.         kr &= 0xff;    /* extended code byte.            */
  349.     fn_dir = 0;        /* Default tab direction if backward.    */
  350.     switch (kr) {
  351.         case CR:
  352.                 /* Look for a DEFAULT object.        */
  353.             fn_obj = NIL;
  354.             map_tree(tree, ROOT, NIL, find_def);
  355.                 /* If found, SELECT and force exit.    */
  356.             if (fn_obj != NIL) {
  357.                 *okr = 0;    /* Zap character.            */
  358.                 objc_sel(tree, fn_obj);
  359.                 *out_obj = fn_obj;
  360.                 return (FALSE);
  361.             }        /* Falls through to     */ 
  362.         case TAB:            /* tab if no default     */
  363.         case DOWN:    
  364.             fn_dir = 1;        /* Set fwd direction     */
  365.         case BTAB:
  366.         case UP:
  367.             fn_last = edit_obj;
  368.             fn_prev = fn_obj = NIL; /* Look for TAB object    */
  369.             map_tree(tree, ROOT, NIL, find_tab);
  370.             if (fn_obj == NIL)    /* try to wrap around     */
  371.                 map_tree(tree, ROOT, NIL, find_tab);
  372.             if (fn_obj != NIL) {
  373.                 *out_obj = fn_obj;
  374.                 *okr = 0;        /* Zap character    */
  375.             }
  376.             break;
  377.         default:            /* Pass other chars    */
  378.             return (TRUE);
  379.         }
  380.     return (TRUE);
  381. }
  382.  
  383. /************* Mouse button manager and subroutines ***************/
  384.  
  385. static void do_radio(GEMrawobject* tree, int obj)
  386. {
  387.     GRect    root;
  388.     int    pobj, sobj;
  389.  
  390.     objc_xywh(tree, ROOT, &root);
  391.     pobj = get_parent(tree, obj);        /* Get the object's parent */
  392.  
  393.     for (sobj = tree[pobj].Head(); sobj != pobj;
  394.         sobj = tree[sobj].Next() )
  395.         {                /* Deselect all but...       */
  396.         if (sobj != obj)
  397.             objc_dsel(tree, sobj);
  398.         }
  399.     objc_sel(tree, obj);            /* the one being SELECTED  */
  400. }
  401.  
  402. /* Mouse button handler       */
  403. static int form_butn(GEMrawobject* tree, int obj, int clicks, int *next_obj, int *hot_obj)
  404. {
  405.     int    flags, state, hibit, texit, sble, dsbld, edit;
  406.     int    in_state;
  407.  
  408.     flags = tree[obj].Flags();        /* Get flags and states   */
  409.     state = tree[obj].States();
  410.     texit = flags & TOUCHEXIT;
  411.     sble = flags & SELECTABLE;
  412.     dsbld = state & DISABLED;
  413.     edit = flags & EDITABLE;
  414.  
  415.     if (!texit && (!sble || dsbld) && !edit) /* This is not an      */
  416.         {                 /* interesting object    */
  417.         *next_obj = 0;
  418.         return (TRUE);
  419.         }
  420.  
  421.     if (texit && clicks == 2)        /* Preset special flag    */
  422.         hibit = 0x8000;
  423.     else
  424.         hibit = 0x0;
  425.  
  426.     if (sble && !dsbld)            /* Hot stuff!        */
  427.         {
  428.         if (flags & RBUTTON)        /* Process radio buttons*/
  429.             do_radio(tree, obj);    /* immediately!        */ 
  430.         else if (!texit)
  431.             {
  432.             in_state = (obj == *hot_obj)?    /* Already toggled ? */
  433.             state: state ^ SELECTED;    
  434.  
  435.             if (!graf_watchbox(tree, obj, in_state, 
  436.                 in_state ^ SELECTED))
  437.                 {            /* He gave up...  */
  438.                 *next_obj = 0;
  439.                 *hot_obj = NIL;
  440.                 return (TRUE);
  441.                 }
  442.             }
  443.         else /* if (texit) */
  444.             if (obj != *hot_obj)    /* Force SELECTED    */
  445.                 objc_toggle(tree, obj);
  446.         }
  447.  
  448.     if (obj == *hot_obj)        /* We're gonna do it! So don't    */
  449.         *hot_obj = NIL;        /* turn it off later.        */
  450.  
  451.     if (texit || (flags & EXIT) )    /* Exit conditions.        */
  452.         {
  453.         *next_obj = obj | hibit;
  454.         return (FALSE);        /* Time to leave!        */
  455.         }
  456.     else if (!edit)            /* Clear object unless tabbing    */
  457.         *next_obj = 0;
  458.  
  459.     return (TRUE);
  460. }
  461.  
  462. static int to_find;
  463. static int FindToFind(GEMrawobject* o, int i)
  464. {
  465.     return i==to_find ? i : -1;
  466. }
  467.  
  468.  
  469. /************* New forms manager: main loop *************/
  470.  
  471. int GEMhotform::FormDo()
  472. {
  473.     int    edit_obj;
  474.     int        next_obj, hot_obj, hot_mode;
  475.     int        which, cont;
  476.     int        idx;
  477.     int        mx, my, mb, meta, kr, br;
  478.     GRect        hot_rect;
  479.  
  480.     wind_update(BEG_MCTRL);
  481.  
  482.     /* Init. editing    */
  483.     to_find=curedit;
  484.     if (Map(FindToFind)!=to_find) // Is it hidden?
  485.         curedit=Map(FindEdit);
  486.     next_obj = curedit;
  487.     edit_obj = 0;
  488.                         /* Initial hotspot cndx */
  489.     hot_obj = NIL; hot_mode = M1_ENTER;
  490.     objc_xywh(Obj, ROOT, &hot_rect);
  491.                         /* Main event loop    */
  492.     cont = TRUE;
  493.     while (cont) {
  494.                         /* position cursor on    */
  495.                         /*   the selected     */
  496.                         /*   editting field    */
  497.         if (edit_obj!=next_obj && next_obj!=0) {
  498.             edit_obj = next_obj;
  499.             next_obj = 0;
  500.             objc_edit(Obj, edit_obj, 0, idx, EDINIT, &idx);
  501.         }
  502.                         /* wait for button or   */
  503.                         /* key or rectangle    */
  504.         which = evnt_multi(MU_KEYBD | MU_BUTTON | MU_M1, 
  505.             0x01, // WWA - Only single click - else race can occur between clicks
  506.             0x01, 0x01,
  507.             hot_mode, hot_rect.g_x, hot_rect.g_y, 
  508.                 hot_rect.g_w, hot_rect.g_h, 
  509.             0, 0, 0, 0, 0,
  510.             0x0L,
  511.             0,
  512.             &mx, &my, &mb, &meta, &kr, &br);
  513.  
  514.         if (which & MU_M1) {            /* handle rect. event     */
  515.             if (hot_obj != NIL) {
  516.                 int h=DoHot(hot_obj,FALSE);
  517.                 if (h!=Ignore) {
  518.                     next_obj=h;
  519.                     cont=FALSE;
  520.                 }
  521.             }
  522.  
  523.             if (cont) {
  524.                 hot_obj = form_hot(Obj, hot_obj, mx, my, &hot_rect, &hot_mode);
  525.  
  526.                 if (hot_obj != NIL) {
  527.                     int h=DoHot(hot_obj,TRUE);
  528.                     if (h!=Ignore) {
  529.                         next_obj=h;
  530.                         cont=FALSE;
  531.                     }
  532.                 }
  533.             }
  534.         }
  535.  
  536.         if (which & MU_KEYBD) { /* handle keyboard event*/
  537.             /* Control char filter    */
  538.             cont = form_keyboard(Obj, edit_obj, next_obj, kr, &next_obj, &kr);
  539.             if (kr) {
  540.                 int k=DoKey(meta,kr);
  541.                 if (k!=Ignore) {
  542.                     next_obj=k;
  543.                     cont=FALSE;
  544.                 } else {
  545.                     if (edit_obj>0) {
  546.                         objc_edit(Obj, edit_obj, kr, idx, EDCHAR, &idx);
  547.                     }
  548.                 }
  549.             }
  550.           }
  551.                         /* handle button event    */
  552.         if (which & MU_BUTTON) {
  553.             /* Which object hit?    */
  554.             next_obj = objc_find(Obj, ROOT, MAX_DEPTH, mx, my);
  555.              if (next_obj == NIL) {
  556.                 next_obj = DoOff();
  557.                 if (next_obj==NoObject) {
  558.                     cont = FALSE; // We want non-form click to cancel form
  559.                 }
  560.             } else {
  561.                     /* Process a click    */
  562.                 // UnHot the object, rather than expecting form_butn to deal with it.
  563.                 if (hot_obj != NIL) {
  564.                     DoHot(hot_obj,FALSE);
  565.                     hot_obj=NIL;
  566.                 }
  567.                 cont = form_butn(Obj, next_obj, br, &next_obj, &hot_obj);
  568.             }
  569.           }
  570.                         /* handle end of field    */
  571.                         /*   clean up        */
  572.         if (!cont || (next_obj != edit_obj && next_obj != 0))
  573.         if (edit_obj != 0) 
  574.           objc_edit(Obj, edit_obj, 0, idx, EDEND, &idx);
  575.     }
  576.                         /* If defaulted, may    */
  577.                         /* need to clear hotspot*/
  578.     if (hot_obj != (next_obj & 0x7fff))
  579.         if (hot_obj != NIL)
  580.             DoHot(hot_obj,FALSE);
  581.                         /* return exit object    */
  582.                         /*   hi bit may be set    */
  583.                         /*   if exit obj. was    */
  584.                         /*   double-clicked    */
  585.     curedit = edit_obj;
  586.  
  587.     wind_update(END_MCTRL);
  588.  
  589.     return(next_obj);
  590. }
  591.